#include <unistd.h>
#include <time.h>
#include "logger.hpp"
#include "transContentSetting.hpp"

const int logger::LEVEL_INFO = 1;
const int logger::LEVEL_NOTICE = 2;
const int logger::LEVEL_WARMMING = 3;        
const int logger::LEVEL_ERROR = 4; 
const int logger::LEVEL_FATA_ERROR = 5;

const int logger::STYLE_HTML = 1;
const int logger::STYLE_TEXT = 2;


const char* logger::css_class_info="info";
const char* logger::css_class_notice="notice";
const char* logger::css_class_warmming="warmming";
const char* logger::css_class_error="lerror";
const char* logger::css_class_fata_error="fata_error";

logger* logger::_instance=NULL;

logger* logger::getInstance(const char* path, int logStyle){
	if(_instance == NULL){
		_instance = new logger(path, logStyle);
		if(_instance->getState() != INS_STATE_OK){
			releaseInstance();
		}
	}
	return _instance;
}

logger::logger(const char* path, int logStyle){
	mState = INS_STATE_ERROR;

	//check parameter
	if(path == NULL || (logStyle != STYLE_HTML && logStyle != STYLE_TEXT)){
#ifdef MDEBUG
		printf("check parameter for logger construct failed\n");
#endif //MDEBUG
		return;
	}

	//alloc space to store filepath
	mfilePath = (char*)calloc(strlen(path)+8, 1);
	if(mfilePath == NULL){
#ifdef MDEBUG
		printf("alloc memory for filePath filed\n");
		perror("calloc");
#endif //MDEBUG		
		return;
	}
	memcpy(this->mfilePath, path, strlen(path));

	//set file name postfix
	mlogStyle = logStyle;
	if(logStyle == STYLE_HTML){
		//the file name not end with html
		if(strlen(strstr(this->mfilePath, ".html")) != 5){
			strcat(this->mfilePath,".html");
		}
	}else{
		if(strlen(strstr(this->mfilePath, ".log")) != 4){
			strcat(this->mfilePath,".log");
		}
	}

	//open logfile to write
	logFile = fopen(this->mfilePath, "w+");
	if(logFile == NULL){
#ifdef MDEBUG
		printf("open log file filed\n");
		perror("fopen");
#endif //MDEBUG	
		return;
	}

	//init log header
	if(mlogStyle == STYLE_HTML){
		init_logstyle_html();
	}else{
		init_logstyle_text();
	}

	flushInterval = TransContentSetting::getLogFlushInterVal();

	//create flush thread 
	pthread_create(&flushThread, NULL, logger::flushLog, this);
	pthread_detach(flushThread);

	//init mutex
	pthread_mutex_init(&mMutexWrite, NULL);

	mState = INS_STATE_OK;
}

logger::~logger(){
	//write end part
	if(mlogStyle == STYLE_HTML){
		end_logstyle_html();
	}else{
		end_logstyle_text();
	}

	//cancel thread
	if(mState == INS_STATE_OK){
		pthread_cancel(flushThread);
		pthread_mutex_destroy(&mMutexWrite);
	}

	//destroy filename
	if(mfilePath != NULL){
		free(mfilePath);
		mfilePath = NULL;
	}

	//close file
	if(logFile != NULL){
		fclose(logFile);
	}
	mState = INS_STATE_ERROR;
}

void logger::releaseInstance(){
	if(logger::_instance != NULL){
#ifdef MDEBUG
		printf("begin to release the logger instance\n");
#endif //MDEBUG
		delete _instance;
		_instance = NULL;
	}
}

void logger::init_logstyle_html(){
	fprintf(logFile, "%s", "<head>\n<title>transformerAndSwitcher-Content</title>\n<style type=text/css>\nbody {\n font-family: sans-serif;\n  font-style:normal;\n   font-size:14px;\n}\n\n.info{\n    color:#000000;\n}\n\n.notice{\n    color:#CD7054;\n}\n\n.lerror{\n    color:#DC143C;\n}\n\n.warmming{\n    color:#8B1A1A;\n}\n\n.fata_error{\n    color:#FF0000;\n}\n</style>\n</head>\n<body>\n");
	writeTimeStamp();
	fprintf(logFile, "\n\n");
}

void logger::init_logstyle_text(){
	writeTimeStamp();
	fprintf(logFile, "\n\n");
}

void logger::writeTimeStamp(){
	time_t timep;
	fprintf(logFile, "%s", asctime(gmtime(&timep))); 	
}

void logger::end_logstyle_html(){
	fprintf(logFile, "%s\n", "</body>");
	fclose(logFile);
}

void logger::end_logstyle_text(){
	fclose(logFile);
}

void logger::logflush(){
	while(1){
		fflush(logFile);
		//delay flushInterval seconds then flush again
		sleep(flushInterval);
	}
}

int logger::appendInfo(int level,const char* format,...){
	if(_instance == NULL || mState != INS_STATE_OK){
#ifdef MDEBUG
		printf("test instance and mState failed\n");
#endif //MEDBUG
		return E_TRANC_InsStateFailed;
	}

	if(level < LEVEL_INFO || level > LEVEL_FATA_ERROR){
#ifdef MDEBUG
		printf("invalidate level\n");
#endif //MEDBUG
		return E_TRANC_ParamError;
	}

	//write html style
	if(mlogStyle == STYLE_HTML){
		if(level == LEVEL_INFO){
			fprintf(logFile, "<li class=\"%s\">\n", css_class_info);
		}else if(level == LEVEL_NOTICE){
			fprintf(logFile, "<li class=\"%s\">\n", css_class_notice);
		}else if(level == LEVEL_WARMMING){
			fprintf(logFile, "<li class=\"%s\">\n", css_class_warmming);
		}else if(level == LEVEL_ERROR){
			fprintf(logFile, "<li class=\"%s\">\n", css_class_error);
		}else{
			fprintf(logFile, "<li class=\"%s\">\n", css_class_fata_error);
		}
	}

	//write content
	va_list apl;
	va_start(apl,format);
	vfprintf(logFile, format, apl);
	va_end(apl);

	//write html style end
	if(mlogStyle == STYLE_HTML){
		fprintf(logFile, "</li>");
	}

	//write newline
	fprintf(logFile, "\n");
	return E_TRANC_SUCESS;
}

int logger::appendDetail(int line, const char* functionName, const char* sourceName, int level, const char* format,...){
	if(_instance == NULL || mState != INS_STATE_OK){
#ifdef MDEBUG
		printf("test instance and mState failed\n");
#endif //MEDBUG
		return E_TRANC_InsStateFailed;
	}

	if(level < LEVEL_INFO || level > LEVEL_FATA_ERROR){
#ifdef MDEBUG
		printf("invalidate level\n");
#endif //MEDBUG
		return E_TRANC_ParamError;
	}

	//write html style
	if(mlogStyle == STYLE_HTML){
		if(level == LEVEL_INFO){
			fprintf(logFile, "<li class=\"%s\">\n", css_class_info);
		}else if(level == LEVEL_NOTICE){
			fprintf(logFile, "<li class=\"%s\">\n", css_class_notice);
		}else if(level == LEVEL_WARMMING){
			fprintf(logFile, "<li class=\"%s\">\n", css_class_warmming);
		}else if(level == LEVEL_ERROR){
			fprintf(logFile, "<li class=\"%s\">\n", css_class_error);
		}else{
			fprintf(logFile, "<li class=\"%s\">\n",css_class_fata_error);
		}
	}

	//write line number function name
	fprintf(logFile, "at source: %s; function: %s line: %d\t", sourceName, functionName, line);	

	//write content
	va_list apl;
	va_start(apl,format);
	vfprintf(logFile, format, apl);
	va_end(apl);

	//write html style end
	if(mlogStyle == STYLE_HTML){
		fprintf(logFile, "</li>");
	}

	//write newline
	fprintf(logFile, "\n");
	return E_TRANC_SUCESS;	
}

void* logger::flushLog(void* p){
	//sleep two second, let the class construct successfully
	sleep(2);
	if(p == NULL){
#ifdef MDEBUG
		printf("test instance and mState failed\n");
#endif //MEDBUG
		return NULL;
	}
	((logger*)p)->logflush();
}

int logger::getState(){
	return mState;
}

int logger::getLogFile(char* buffer, int len){
	int pathLen = strlen(mfilePath);
	if(pathLen >= len){
		return E_TRANC_BufferTooSmall;
	}
	memset(buffer, 0x00, len);
	memcpy(buffer, mfilePath, pathLen);
	return E_TRANC_SUCESS;
}

int logger::getLogStyle(){
	return mlogStyle;
}

int logger::getFlushInterval(){
	return flushInterval;
}
